home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / m_move.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  11.8 KB  |  557 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // m_move.c -- monster movement
  21.  
  22. #include "g_local.h"
  23.  
  24. #define    STEPSIZE    18
  25.  
  26. /*
  27. =============
  28. M_CheckBottom
  29.  
  30. Returns false if any part of the bottom of the entity is off an edge that
  31. is not a staircase.
  32.  
  33. =============
  34. */
  35. int c_yes, c_no;
  36.  
  37. qboolean M_CheckBottom (edict_t *ent)
  38. {
  39.     vec3_t    mins, maxs, start, stop;
  40.     trace_t    trace;
  41.     int        x, y;
  42.     float    mid, bottom;
  43.     
  44.     VectorAdd (ent->s.origin, ent->mins, mins);
  45.     VectorAdd (ent->s.origin, ent->maxs, maxs);
  46.  
  47. // if all of the points under the corners are solid world, don't bother
  48. // with the tougher checks
  49. // the corners must be within 16 of the midpoint
  50.     start[2] = mins[2] - 1;
  51.     for    (x=0 ; x<=1 ; x++)
  52.         for    (y=0 ; y<=1 ; y++)
  53.         {
  54.             start[0] = x ? maxs[0] : mins[0];
  55.             start[1] = y ? maxs[1] : mins[1];
  56.             if (gi.pointcontents (start) != CONTENTS_SOLID)
  57.                 goto realcheck;
  58.         }
  59.  
  60.     c_yes++;
  61.     return true;        // we got out easy
  62.  
  63. realcheck:
  64.     c_no++;
  65. //
  66. // check it for real...
  67. //
  68.     start[2] = mins[2];
  69.     
  70. // the midpoint must be within 16 of the bottom
  71.     start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
  72.     start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
  73.     stop[2] = start[2] - 2*STEPSIZE;
  74.     trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  75.  
  76.     if (trace.fraction == 1.0)
  77.         return false;
  78.     mid = bottom = trace.endpos[2];
  79.     
  80. // the corners must be within 16 of the midpoint    
  81.     for    (x=0 ; x<=1 ; x++)
  82.         for    (y=0 ; y<=1 ; y++)
  83.         {
  84.             start[0] = stop[0] = x ? maxs[0] : mins[0];
  85.             start[1] = stop[1] = y ? maxs[1] : mins[1];
  86.             
  87.             trace = gi.trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID);
  88.             
  89.             if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
  90.                 bottom = trace.endpos[2];
  91.             if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)
  92.                 return false;
  93.         }
  94.  
  95.     c_yes++;
  96.     return true;
  97. }
  98.  
  99.  
  100. /*
  101. =============
  102. SV_movestep
  103.  
  104. Called by monster program code.
  105. The move will be adjusted for slopes and stairs, but if the move isn't
  106. possible, no move is done, false is returned, and
  107. pr_global_struct->trace_normal is set to the normal of the blocking wall
  108. =============
  109. */
  110. //FIXME since we need to test end position contents here, can we avoid doing
  111. //it again later in catagorize position?
  112. qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink)
  113. {
  114.     float        dz;
  115.     vec3_t        oldorg, neworg, end;
  116.     trace_t        trace;
  117.     int            i;
  118.     float        stepsize;
  119.     vec3_t        test;
  120.     int            contents;
  121.  
  122. // try the move    
  123.     VectorCopy (ent->s.origin, oldorg);
  124.     VectorAdd (ent->s.origin, move, neworg);
  125.  
  126. // flying monsters don't step up
  127.     if ( ent->flags & (FL_SWIM | FL_FLY) )
  128.     {
  129.     // try one move with vertical motion, then one without
  130.         for (i=0 ; i<2 ; i++)
  131.         {
  132.             VectorAdd (ent->s.origin, move, neworg);
  133.             if (i == 0 && ent->enemy)
  134.             {
  135.                 if (!ent->goalentity)
  136.                     ent->goalentity = ent->enemy;
  137.                 dz = ent->s.origin[2] - ent->goalentity->s.origin[2];
  138.                 if (ent->goalentity->client)
  139.                 {
  140.                     if (dz > 40)
  141.                         neworg[2] -= 8;
  142.                     if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2)))
  143.                         if (dz < 30)
  144.                             neworg[2] += 8;
  145.                 }
  146.                 else
  147.                 {
  148.                     if (dz > 8)
  149.                         neworg[2] -= 8;
  150.                     else if (dz > 0)
  151.                         neworg[2] -= dz;
  152.                     else if (dz < -8)
  153.                         neworg[2] += 8;
  154.                     else
  155.                         neworg[2] += dz;
  156.                 }
  157.             }
  158.             trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID);
  159.     
  160.             // fly monsters don't enter water voluntarily
  161.             if (ent->flags & FL_FLY)
  162.             {
  163.                 if (!ent->waterlevel)
  164.                 {
  165.                     test[0] = trace.endpos[0];
  166.                     test[1] = trace.endpos[1];
  167.                     test[2] = trace.endpos[2] + ent->mins[2] + 1;
  168.                     contents = gi.pointcontents(test);
  169.                     if (contents & MASK_WATER)
  170.                         return false;
  171.                 }
  172.             }
  173.  
  174.             // swim monsters don't exit water voluntarily
  175.             if (ent->flags & FL_SWIM)
  176.             {
  177.                 if (ent->waterlevel < 2)
  178.                 {
  179.                     test[0] = trace.endpos[0];
  180.                     test[1] = trace.endpos[1];
  181.                     test[2] = trace.endpos[2] + ent->mins[2] + 1;
  182.                     contents = gi.pointcontents(test);
  183.                     if (!(contents & MASK_WATER))
  184.                         return false;
  185.                 }
  186.             }
  187.  
  188.             if (trace.fraction == 1)
  189.             {
  190.                 VectorCopy (trace.endpos, ent->s.origin);
  191.                 if (relink)
  192.                 {
  193.                     gi.linkentity (ent);
  194.                     G_TouchTriggers (ent);
  195.                 }
  196.                 return true;
  197.             }
  198.             
  199.             if (!ent->enemy)
  200.                 break;
  201.         }
  202.         
  203.         return false;
  204.     }
  205.  
  206. // push down from a step height above the wished position
  207.     if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
  208.         stepsize = STEPSIZE;
  209.     else
  210.         stepsize = 1;
  211.  
  212.     neworg[2] += stepsize;
  213.     VectorCopy (neworg, end);
  214.     end[2] -= stepsize*2;
  215.  
  216.     trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  217.  
  218.     if (trace.allsolid)
  219.         return false;
  220.  
  221.     if (trace.startsolid)
  222.     {
  223.         neworg[2] -= stepsize;
  224.         trace = gi.trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID);
  225.         if (trace.allsolid || trace.startsolid)
  226.             return false;
  227.     }
  228.  
  229.  
  230.     // don't go in to water
  231.     if (ent->waterlevel == 0)
  232.     {
  233.         test[0] = trace.endpos[0];
  234.         test[1] = trace.endpos[1];
  235.         test[2] = trace.endpos[2] + ent->mins[2] + 1;    
  236.         contents = gi.pointcontents(test);
  237.  
  238.         if (contents & MASK_WATER)
  239.             return false;
  240.     }
  241.  
  242.     if (trace.fraction == 1)
  243.     {
  244.     // if monster had the ground pulled out, go ahead and fall
  245.         if ( ent->flags & FL_PARTIALGROUND )
  246.         {
  247.             VectorAdd (ent->s.origin, move, ent->s.origin);
  248.             if (relink)
  249.             {
  250.                 gi.linkentity (ent);
  251.                 G_TouchTriggers (ent);
  252.             }
  253.             ent->groundentity = NULL;
  254.             return true;
  255.         }
  256.     
  257.         return false;        // walked off an edge
  258.     }
  259.  
  260. // check point traces down for dangling corners
  261.     VectorCopy (trace.endpos, ent->s.origin);
  262.     
  263.     if (!M_CheckBottom (ent))
  264.     {
  265.         if ( ent->flags & FL_PARTIALGROUND )
  266.         {    // entity had floor mostly pulled out from underneath it
  267.             // and is trying to correct
  268.             if (relink)
  269.             {
  270.                 gi.linkentity (ent);
  271.                 G_TouchTriggers (ent);
  272.             }
  273.             return true;
  274.         }
  275.         VectorCopy (oldorg, ent->s.origin);
  276.         return false;
  277.     }
  278.  
  279.     if ( ent->flags & FL_PARTIALGROUND )
  280.     {
  281.         ent->flags &= ~FL_PARTIALGROUND;
  282.     }
  283.     ent->groundentity = trace.ent;
  284.     ent->groundentity_linkcount = trace.ent->linkcount;
  285.  
  286. // the move is ok
  287.     if (relink)
  288.     {
  289.         gi.linkentity (ent);
  290.         G_TouchTriggers (ent);
  291.     }
  292.     return true;
  293. }
  294.  
  295.  
  296. //============================================================================
  297.  
  298. /*
  299. ===============
  300. M_ChangeYaw
  301.  
  302. ===============
  303. */
  304. void M_ChangeYaw (edict_t *ent)
  305. {
  306.     float    ideal;
  307.     float    current;
  308.     float    move;
  309.     float    speed;
  310.     
  311.     current = anglemod(ent->s.angles[YAW]);
  312.     ideal = ent->ideal_yaw;
  313.  
  314.     if (current == ideal)
  315.         return;
  316.  
  317.     move = ideal - current;
  318.     speed = ent->yaw_speed;
  319.     if (ideal > current)
  320.     {
  321.         if (move >= 180)
  322.             move = move - 360;
  323.     }
  324.     else
  325.     {
  326.         if (move <= -180)
  327.             move = move + 360;
  328.     }
  329.     if (move > 0)
  330.     {
  331.         if (move > speed)
  332.             move = speed;
  333.     }
  334.     else
  335.     {
  336.         if (move < -speed)
  337.             move = -speed;
  338.     }
  339.     
  340.     ent->s.angles[YAW] = anglemod (current + move);
  341. }
  342.  
  343.  
  344. /*
  345. ======================
  346. SV_StepDirection
  347.  
  348. Turns to the movement direction, and walks the current distance if
  349. facing it.
  350.  
  351. ======================
  352. */
  353. qboolean SV_StepDirection (edict_t *ent, float yaw, float dist)
  354. {
  355.     vec3_t        move, oldorigin;
  356.     float        delta;
  357.     
  358.     ent->ideal_yaw = yaw;
  359.     M_ChangeYaw (ent);
  360.     
  361.     yaw = yaw*M_PI*2 / 360;
  362.     move[0] = cos(yaw)*dist;
  363.     move[1] = sin(yaw)*dist;
  364.     move[2] = 0;
  365.  
  366.     VectorCopy (ent->s.origin, oldorigin);
  367.     if (SV_movestep (ent, move, false))
  368.     {
  369.         delta = ent->s.angles[YAW] - ent->ideal_yaw;
  370.         if (delta > 45 && delta < 315)
  371.         {        // not turned far enough, so don't take the step
  372.             VectorCopy (oldorigin, ent->s.origin);
  373.         }
  374.         gi.linkentity (ent);
  375.         G_TouchTriggers (ent);
  376.         return true;
  377.     }
  378.     gi.linkentity (ent);
  379.     G_TouchTriggers (ent);
  380.     return false;
  381. }
  382.  
  383. /*
  384. ======================
  385. SV_FixCheckBottom
  386.  
  387. ======================
  388. */
  389. void SV_FixCheckBottom (edict_t *ent)
  390. {
  391.     ent->flags |= FL_PARTIALGROUND;
  392. }
  393.  
  394.  
  395.  
  396. /*
  397. ================
  398. SV_NewChaseDir
  399.  
  400. ================
  401. */
  402. #define    DI_NODIR    -1
  403. void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)
  404. {
  405.     float    deltax,deltay;
  406.     float    d[3];
  407.     float    tdir, olddir, turnaround;
  408.  
  409.     //FIXME: how did we get here with no enemy
  410.     if (!enemy)
  411.         return;
  412.  
  413.     olddir = anglemod( (int)(actor->ideal_yaw/45)*45 );
  414.     turnaround = anglemod(olddir - 180);
  415.  
  416.     deltax = enemy->s.origin[0] - actor->s.origin[0];
  417.     deltay = enemy->s.origin[1] - actor->s.origin[1];
  418.     if (deltax>10)
  419.         d[1]= 0;
  420.     else if (deltax<-10)
  421.         d[1]= 180;
  422.     else
  423.         d[1]= DI_NODIR;
  424.     if (deltay<-10)
  425.         d[2]= 270;
  426.     else if (deltay>10)
  427.         d[2]= 90;
  428.     else
  429.         d[2]= DI_NODIR;
  430.  
  431. // try direct route
  432.     if (d[1] != DI_NODIR && d[2] != DI_NODIR)
  433.     {
  434.         if (d[1] == 0)
  435.             tdir = d[2] == 90 ? 45 : 315;
  436.         else
  437.             tdir = d[2] == 90 ? 135 : 215;
  438.             
  439.         if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
  440.             return;
  441.     }
  442.  
  443. // try other directions
  444.     if ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))
  445.     {
  446.         tdir=d[1];
  447.         d[1]=d[2];
  448.         d[2]=tdir;
  449.     }
  450.  
  451.     if (d[1]!=DI_NODIR && d[1]!=turnaround 
  452.     && SV_StepDirection(actor, d[1], dist))
  453.             return;
  454.  
  455.     if (d[2]!=DI_NODIR && d[2]!=turnaround
  456.     && SV_StepDirection(actor, d[2], dist))
  457.             return;
  458.  
  459. /* there is no direct path to the player, so pick another direction */
  460.  
  461.     if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))
  462.             return;
  463.  
  464.     if (rand()&1)     /*randomly determine direction of search*/
  465.     {
  466.         for (tdir=0 ; tdir<=315 ; tdir += 45)
  467.             if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  468.                     return;
  469.     }
  470.     else
  471.     {
  472.         for (tdir=315 ; tdir >=0 ; tdir -= 45)
  473.             if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )
  474.                     return;
  475.     }
  476.  
  477.     if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )
  478.             return;
  479.  
  480.     actor->ideal_yaw = olddir;        // can't move
  481.  
  482. // if a bridge was pulled out from underneath a monster, it may not have
  483. // a valid standing position at all
  484.  
  485.     if (!M_CheckBottom (actor))
  486.         SV_FixCheckBottom (actor);
  487. }
  488.  
  489. /*
  490. ======================
  491. SV_CloseEnough
  492.  
  493. ======================
  494. */
  495. qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)
  496. {
  497.     int        i;
  498.     
  499.     for (i=0 ; i<3 ; i++)
  500.     {
  501.         if (goal->absmin[i] > ent->absmax[i] + dist)
  502.             return false;
  503.         if (goal->absmax[i] < ent->absmin[i] - dist)
  504.             return false;
  505.     }
  506.     return true;
  507. }
  508.  
  509.  
  510. /*
  511. ======================
  512. M_MoveToGoal
  513. ======================
  514. */
  515. void M_MoveToGoal (edict_t *ent, float dist)
  516. {
  517.     edict_t        *goal;
  518.     
  519.     goal = ent->goalentity;
  520.  
  521.     if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  522.         return;
  523.  
  524. // if the next step hits the enemy, return immediately
  525.     if (ent->enemy &&  SV_CloseEnough (ent, ent->enemy, dist) )
  526.         return;
  527.  
  528. // bump around...
  529.     if ( (rand()&3)==1 || !SV_StepDirection (ent, ent->ideal_yaw, dist))
  530.     {
  531.         if (ent->inuse)
  532.             SV_NewChaseDir (ent, goal, dist);
  533.     }
  534. }
  535.  
  536.  
  537. /*
  538. ===============
  539. M_walkmove
  540. ===============
  541. */
  542. qboolean M_walkmove (edict_t *ent, float yaw, float dist)
  543. {
  544.     vec3_t    move;
  545.     
  546.     if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM)))
  547.         return false;
  548.  
  549.     yaw = yaw*M_PI*2 / 360;
  550.     
  551.     move[0] = cos(yaw)*dist;
  552.     move[1] = sin(yaw)*dist;
  553.     move[2] = 0;
  554.  
  555.     return SV_movestep(ent, move, true);
  556. }
  557.